#if NEW_INPUT_SYSTEM

using Devil;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.InputSystem.LowLevel;

namespace GameToolkit
{
    public class NewInputKeyboard : InputController
    {
        [SerializeField]
        bool m_IsReadyToUse;

        List<KeyInfo> mKeys;
        public override EControllerType ControllerType => EControllerType.Keyboard;

        //IDisposable mBindingEvents;
        Keyboard mKeyboard;
        Mouse mMouse;

        public override void Prepare(GameInput ginput)
        {
            base.Prepare(ginput);
            mKeys = new List<KeyInfo>();
            for (int i = 1; i <= 10; i++)
            {
                var key = new KeyInfo(EControllerType.Keyboard, false, ECustomizableKey.Customizable, Localization.ToString(i % 10), (int)Key.Digit1 + i - 1);
                mKeys.Add(key);
            }
            for (int c = 'A'; c <= 'Z'; c++)
            {
                var key = new KeyInfo(EControllerType.Keyboard, false, ECustomizableKey.Customizable, ((char)c).ToString(), (int)Key.A + (c - 'A'));
                mKeys.Add(key);
            }

            mKeys.Add(new KeyInfo(EControllerType.Keyboard, false, ECustomizableKey.Customizable, "SPACE", (int)Key.Space));

            mKeys.Add(new KeyInfo(EControllerType.Keyboard, false, ECustomizableKey.Customizable, "Left", (int)Key.LeftArrow));
            mKeys.Add(new KeyInfo(EControllerType.Keyboard, false, ECustomizableKey.Customizable, "Right", (int)Key.RightArrow));
            mKeys.Add(new KeyInfo(EControllerType.Keyboard, false, ECustomizableKey.Customizable, "Up", (int)Key.UpArrow));
            mKeys.Add(new KeyInfo(EControllerType.Keyboard, false, ECustomizableKey.Customizable, "Down", (int)Key.DownArrow));

            mKeys.Add(new KeyInfo(EControllerType.Keyboard, false, ECustomizableKey.Customizable, "SHIFT", (int)Key.LeftShift));
            mKeys.Add(new KeyInfo(EControllerType.Keyboard, false, ECustomizableKey.Customizable, "CTRL", (int)Key.LeftCtrl));
            mKeys.Add(new KeyInfo(EControllerType.Keyboard, false, ECustomizableKey.Customizable, "ALT", (int)Key.LeftAlt));

            mKeys.Add(new KeyInfo(EControllerType.Keyboard, false, ECustomizableKey.Customizable, "DEL", (int)Key.Delete));
            mKeys.Add(new KeyInfo(EControllerType.Keyboard, false, ECustomizableKey.Customizable, "BACK", (int)Key.Backspace));

            mKeys.Add(new KeyInfo(EControllerType.Keyboard, false, ECustomizableKey.SystemStart, "ENTER", (int)Key.Enter));
            mKeys.Add(new KeyInfo(EControllerType.Keyboard, false, ECustomizableKey.SystemBack, "ESC", (int)Key.Escape));

            mKeys.Add(new KeyInfo(EControllerType.Mouse, false, ECustomizableKey.Fallback, "Mouse 0", 0));
            mKeys.Add(new KeyInfo(EControllerType.Mouse, false, ECustomizableKey.Customizable, "Mouse 1", 1));
            mKeys.Add(new KeyInfo(EControllerType.Mouse, false, ECustomizableKey.Customizable, "Mouse 2", 2));

            mKeys.Add(new KeyInfo(EControllerType.Mouse, true, ECustomizableKey.Fallback, "Mouse X", 0));
            mKeys.Add(new KeyInfo(EControllerType.Mouse, true, ECustomizableKey.Fallback, "Mouse Y", 1));
            mKeys.Add(new KeyInfo(EControllerType.Mouse, true, ECustomizableKey.Fallback, "Mouse ScrollWheel", 3));

            //Keyboard
            mKeyboard = InputSystem.GetDevice<Keyboard>();
            mMouse = InputSystem.GetDevice<Mouse>();
            m_IsReadyToUse = mKeyboard != null || mMouse != null;
            //var keyboard = InputSystem.GetDevice<Keyboard>();
            //keyboard.onTextInput -= OnInputKey;
            //keyboard.onTextInput += OnInputKey;
            //if (mBindingEvents != null)
            //    mBindingEvents.Dispose();
            //mBindingEvents = InputSystem.onEvent.ForDevice<Keyboard>().Call(OnKeyboardEvent); // += OnEvent;
        }

        private void OnInputKey(char obj)
        {
            Debug.Log($"Key: {obj} ({(int)obj})");
        }

#if UNITY_EDITOR
        private void OnValidate()
        {
            m_IsReadyToUse = mKeyboard != null || mMouse != null;
        }
#endif

        void OnKeyboardEvent(InputEventPtr ev)
        {
            var btn = ev.GetFirstButtonPressOrNull();
            Debug.LogFormat("OnEvent: {0} #{1}", ev, btn?.displayName);
        }

        public override IInputAction GetAction(string keyName)
        {
            if (mKeys != null && mKeyboard != null)
            {
                for (int i = 0; i < mKeys.Count; i++)
                {
                    var key = mKeys[i];
                    if (key.keyName.EqualsIgnoreCase(keyName))
                    {
                        if (key.isAxis)
                            return new MouseMovment(this, key);
                        else
                            return new KeyAction(this, key);
                    }
                }
            }
            return null;
        }

        public override KeyInfo[] GetKeysInfo()
        {
            return mKeys == null ? new KeyInfo[0] : mKeys.ToArray();
        }

        public override bool IsKindOf(EControllerType type)
        {
            return type == EControllerType.Keyboard || type == EControllerType.Mouse;
        }

        protected override bool TestConnection()
        {
            return m_IsReadyToUse;
        }


        class KeyAction : IInputAction
        {
            KeyInfo mKey;
            InputController mCtrl;
            ButtonControl mKeyCtrl;
            internal KeyAction(NewInputKeyboard ctrl, KeyInfo info)
            {
                mCtrl = ctrl;
                mKey = info;
                if (info.type == EControllerType.Keyboard && ctrl.mKeyboard != null)
                {
                    var key = (Key)info.keyCode;
                    if (key == Key.LeftShift || key == Key.RightShift)
                        mKeyCtrl = ctrl.mKeyboard.shiftKey;
                    else if (key == Key.LeftCtrl || key == Key.RightCtrl)
                        mKeyCtrl = ctrl.mKeyboard.ctrlKey;
                    else if (key == Key.LeftAlt || key == Key.RightAlt)
                        mKeyCtrl = ctrl.mKeyboard.altKey;
                    else
                        mKeyCtrl = ctrl.mKeyboard[key];
                }
                else if (info.type == EControllerType.Mouse && ctrl.mMouse != null)
                {
                    switch (info.keyCode)
                    {
                        case 0:
                            mKeyCtrl = ctrl.mMouse.leftButton;
                            break;
                        case 1:
                            mKeyCtrl = ctrl.mMouse.rightButton;
                            break;
                        case 2:
                            mKeyCtrl = ctrl.mMouse.middleButton;
                            break;
                        default:
                            break;
                    }
                }
            }
            public InputController Controller => mCtrl;

            public EControllerType ControllerType => mKey.type;

            public float Value => mKeyCtrl != null && mKeyCtrl.isPressed ? 1 : 0;

            public bool HasButton => mKeyCtrl != null && mKeyCtrl.isPressed;

            public KeyInfo GetKeyInfo()
            {
                return mKey;
            }
        }
        class MouseMovment : IInputAction
        {
            KeyInfo mKey;
            InputController mCtrl;
            DeltaControl mMov;
            public InputController Controller => mCtrl;

            public EControllerType ControllerType => mKey.type;

            public float Value
            {
                get
                {
                    var v = mMov == null ? default : mMov.value;
                    if ((mKey.keyCode & 1) == 0)
                        return v.x;
                    else
                        return v.y;
                }
            }

            public bool HasButton => mMov != null && mMov.value != Vector2.zero;

            internal MouseMovment(NewInputKeyboard ctrl, KeyInfo key)
            {
                mCtrl = ctrl;
                mKey = key;
                if (ctrl.mMouse != null)
                {
                    switch (key.keyCode)
                    {
                        // x & y
                        case 0:
                        case 1:
                            mMov = ctrl.mMouse.delta;
                            break;
                        case 2:
                        case 3:
                            mMov = ctrl.mMouse.scroll;
                            break;
                        default:
                            break;
                    }
                }
            }

            public KeyInfo GetKeyInfo()
            {
                return mKey;
            }
        }

    }
}
#endif